using System;
using System.Linq.Expressions;
using System.Reflection;
using Randomize.Core.Exceptions;
using Randomize.Core.Generators;

namespace Randomize.Core.Constructors
{
    public class PropertyConstructor<TComplex, TProperty> : IPropertyConstructor<TComplex, TProperty>
    {
        private readonly IGenerator<TProperty> _generator;

        public Expression<Func<TComplex, TProperty>> PropertyExpression { get; set; }

        public Action<TComplex, TProperty> Setter { get; set; }

        public PropertyConstructor(Expression<Func<TComplex, TProperty>> propertyExpression, IGenerator<TProperty> generator)
        {
            PropertyExpression = propertyExpression;
            _generator = generator;
        }

        public void ConstructProperty(TComplex obj)
        {
            TProperty generatedValue = _generator.Generate();
            
            if (this.Setter != null)
            {
                this.Setter(obj, generatedValue);
            }
            else
            {
                SetProperty(obj, generatedValue);
            }
        }

        private void SetProperty(TComplex obj, TProperty generatedValue)
        {
            var memberExpression = this.PropertyExpression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new InvalidExpressionException(this.PropertyExpression);
            }
            var propertyInfo = memberExpression.Member as PropertyInfo;

            if (propertyInfo == null)
            {
                throw new InvalidExpressionException(this.PropertyExpression);
            }

            propertyInfo.SetValue(obj, generatedValue, null);
        }
    }
}